﻿using System;
using System.Collections.Generic;
using System.Linq;
using Molic.Core.Controls;

namespace Molic.Core.Services
{
    public class MolicSelectionService : Molic.Core.Services.IMolicSelectionService
    {
        private Molic.Core.Controls.interfaces.IMolicCanvas designerCanvas;

        private List<IMolicSelectable> currentSelection;
        public List<IMolicSelectable> CurrentSelection
        {
            get
            {
                if (currentSelection == null)
                    currentSelection = new List<IMolicSelectable>();

                return currentSelection;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="canvas"></param>
        public MolicSelectionService(Molic.Core.Controls.interfaces.IMolicCanvas canvas)
        {
            this.designerCanvas = canvas;
        }
        /// <summary>
        /// Uselect all items and select the item informed and the members of its group.
        /// </summary>
        /// <param name="item"></param>
        public void SelectItem(IMolicSelectable item)
        {
            this.ClearSelection();
            this.AddToSelection(item);
        }
        /// <summary>
        /// Select the item and the members of its group.
        /// </summary>
        /// <param name="item"></param>
        public void AddToSelection(IMolicSelectable item)
        {
            if (item is IMolicGroupable)
            {
                List<IMolicGroupable> groupItems = GetGroupMembers(item as IMolicGroupable);

                foreach (IMolicSelectable groupItem in groupItems)
                {
                    groupItem.IsSelected = true;
                    CurrentSelection.Add(groupItem);
                }
            }
            else
            {
                item.IsSelected = true;
                CurrentSelection.Add(item);
            }
        }
        /// <summary>
        /// Unselect the item from the selection list and the members of its group.
        /// </summary>
        /// <param name="item"></param>
        public void RemoveFromSelection(IMolicSelectable item)
        {
            if (item is IMolicGroupable)
            {
                List<IMolicGroupable> groupItems = GetGroupMembers(item as IMolicGroupable);

                foreach (IMolicSelectable groupItem in groupItems)
                {
                    groupItem.IsSelected = false;
                    CurrentSelection.Remove(groupItem);
                }
            }
            else
            {
                item.IsSelected = false;
                CurrentSelection.Remove(item);
            }
        }
        /// <summary>
        /// Unselect all items.
        /// </summary>
        public void ClearSelection()
        {
            CurrentSelection.ForEach(item => item.IsSelected = false);
            CurrentSelection.Clear();
        }
        /// <summary>
        /// Selects all eleements in the canvas.
        /// </summary>
        public void SelectAll()
        {
            ClearSelection();
            CurrentSelection.AddRange(designerCanvas.Children.OfType<IMolicSelectable>());
            CurrentSelection.ForEach(item => item.IsSelected = true);
        }
        /// <summary>
        /// Gets all members of the same group of the item. 
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public List<IMolicGroupable> GetGroupMembers(IMolicGroupable item)
        {
            IEnumerable<IMolicGroupable> list = designerCanvas.Children.OfType<IMolicGroupable>();
            IMolicGroupable rootItem = GetRoot(list, item);
            return GetGroupMembers(list, rootItem);
        }
        /// <summary>
        /// Gets the group's root element.
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public IMolicGroupable GetGroupRoot(IMolicGroupable item)
        {
            IEnumerable<IMolicGroupable> list = designerCanvas.Children.OfType<IMolicGroupable>();
            return GetRoot(list, item);
        }
        /// <summary>
        /// Searches recursively for the root element of the node.
        /// </summary>
        /// <param name="list"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        private IMolicGroupable GetRoot(IEnumerable<IMolicGroupable> list, IMolicGroupable node)
        {
            if (node == null || node.ParentID == Guid.Empty)
            {
                return node;
            }
            else
            {
                foreach (IMolicGroupable item in list)
                {
                    if (item.ID == node.ParentID)
                    {
                        return GetRoot(list, item);
                    }
                }
                return null;
            }
        }
        /// <summary>
        /// Gets all members of the group recursively.
        /// </summary>
        /// <param name="list"></param>
        /// <param name="parent"></param>
        /// <returns></returns>
        private List<IMolicGroupable> GetGroupMembers(IEnumerable<IMolicGroupable> list, IMolicGroupable parent)
        {
            List<IMolicGroupable> groupMembers = new List<IMolicGroupable>();
            groupMembers.Add(parent);

            var children = list.Where(node => node.ParentID == parent.ID);

            foreach (IMolicGroupable child in children)
            {
                groupMembers.AddRange(GetGroupMembers(list, child));
            }

            return groupMembers;
        }
    }
}
